package com.eidos.blogs.openapi.controller.seckill;

import com.alibaba.fastjson.JSONObject;
import com.eidos.blogs.openapi.constant.NcountKey;
import com.eidos.blogs.openapi.dto.secKill.SecretDto;
import com.eidos.blogs.openapi.rest.HttpCodeEnum;
import com.eidos.blogs.openapi.controller.BaseController;
import com.eidos.blogs.openapi.dto.secKill.GenerateRedEnvelopeDto;
import com.eidos.blogs.openapi.dto.secKill.RedEnvelopeDto;
import com.eidos.blogs.openapi.entity.seckill.RedeReceiveRecord;
import com.eidos.blogs.openapi.rest.Resp;
import com.eidos.blogs.openapi.rest.seckill.request.form.BaseTransForm;
import com.eidos.blogs.openapi.rest.seckill.request.init.InitForm;
import com.eidos.blogs.openapi.service.seckill.IRedEnvelopesService;
import com.eidos.blogs.openapi.utils.*;
import com.eidos.blogs.openapi.vo.secKill.redenvelope.RedEnvelopeVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.security.PrivateKey;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

/**
 * @author ： Eidos
 * @date ：Created in 2020/12/28
 * @description： 秒杀架构-群抢红包
 * @modified By：
 * @version: 1.0
 */

@RestController
@RequestMapping("sec-kill/red-envelopes/common")
@Api(value = "抢红包", tags = "抢红包")
@Slf4j
public class RedEnvelopeController extends BaseController {


    @Resource
    private IRedEnvelopesService iRedEnvelopeService;
    @Resource
    private RedisTemplate redisTemplate;


    @ApiOperation(value = "查询领取红包记录", nickname = "查询领取红包记录")
    @PostMapping("/queryRedeReceiveRecordListByRedEnvelopeId")
    public Resp<List<RedeReceiveRecord>> queryRedeReceiveRecordListByRedEnvelopeId( @Valid @RequestBody GenerateRedEnvelopeDto dto, BindingResult result) {
        try {
            if (result.hasErrors()) {
                return Resp.failed(HttpCodeEnum.PARAM_VAILD_ERROR, result.getAllErrors().get(0).getDefaultMessage());
            }
            return iRedEnvelopeService.queryRedeReceiveRecordListByRedEnvelopeId(dto);
        } catch (Exception e) {
            return Resp.failed(HttpCodeEnum.SYSTEM_ERROR);
        }

    }

    @ApiOperation(value = "生成红包", nickname = "生成红包")
    @PostMapping("/generate_redEnvelope")
    public Resp<Boolean> generateRedEnvelope( @Valid @RequestBody GenerateRedEnvelopeDto dto, BindingResult result) {
        try {
            if (result.hasErrors()) {
                return Resp.failed(HttpCodeEnum.PARAM_VAILD_ERROR, result.getAllErrors().get(0).getDefaultMessage());
            }
            return iRedEnvelopeService.generateRedEnvelope(dto);
        } catch (Exception e) {
            return Resp.failed(HttpCodeEnum.SYSTEM_ERROR);
        }

    }

    @ApiOperation(value = "删除红包", nickname = "删除红包")
    @PostMapping("/delete_redEnvelope")
    public Resp<Boolean> deleteRedEnvelope(HttpServletRequest request, @RequestBody GenerateRedEnvelopeDto dto) {
        try {
            Resp<Boolean> resp = iRedEnvelopeService.deleteRedEnvelope(dto);
            return resp;
        } catch (Exception e) {
            return Resp.failed(HttpCodeEnum.SYSTEM_ERROR);
        }
    }

    @ApiOperation(value = "领取红包", nickname = "领取红包")
    @PostMapping("/receive_redEnvelope")
    public Resp<RedEnvelopeVo> receiveRedEnvelope(HttpServletRequest request, @RequestBody RedEnvelopeDto dto) {
        try {
            Resp<RedEnvelopeVo> resp = iRedEnvelopeService.receiveRedEnvelope(dto);
            return resp;
        } catch (Exception e) {
            e.printStackTrace();
            return Resp.failed(HttpCodeEnum.SYSTEM_ERROR);
        }
    }


    /**
     * 抢红包 拆红包 抢到不一定能拆到
     *
     * @return
     */
//    @ApiOperation(value = "群抢红包并发", nickname = "群抢红包并发")
    public Resp<Boolean> grabConcurrent(HttpServletRequest request, @RequestBody RedEnvelopeDto dto) {
        try {
            String numberKey = "redEnvelope_number_" + dto.getRedEnvelopeId();
            String amountKey = "redEnvelope_amount_" + dto.getRedEnvelopeId();
            int skillNum = 100;
            final CountDownLatch latch = new CountDownLatch(skillNum);//N个抢红包
            /**
             * 模拟100个用户抢10个红包
             */
            for (int i = 1; i <= skillNum; i++) {
                int userId = i;
                Runnable task = () -> {
                    /**
                     * 抢红包 判断剩余金额
                     */
                    Long restMoney = Long.valueOf(redisTemplate.opsForValue().get(amountKey).toString());
                    if (restMoney > 0) {
                        /**
                         * 虽然能抢到 但是不一定能拆到
                         * 类似于微信的 点击红包显示抢的按钮
                         */
                        Resp<Long> resp = iRedEnvelopeService.grabConcurrent(dto);
                        if (resp.getCode() != 200) {
                            log.info("用户" + userId + "手慢了，红包派完了", dto.getUserId());
                        }
                    } else {
                        /**
                         * 直接显示手慢了，红包派完了
                         */
                        log.info("手慢了，红包派完了", userId);
                    }
                    latch.countDown();
                };
//                threadPoolExecutor.execute(task);
            }
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return Resp.failed(HttpCodeEnum.SYSTEM_ERROR);
        }
        return Resp.success(Boolean.TRUE);
    }


    @ApiOperation(value = "获取加密key")
    @PostMapping(value = "/loadPrivateKey.do")
    public Resp<Map> loadPrivateKey(@RequestBody SecretDto dto) {
        try {
            if(StringUtils.isEmpty(dto.getJsonStr()) && StringUtils.isBlank(dto.getJsonStr())){
                return Resp.failed("表单json为空");
            }
            if(StringUtils.isEmpty(dto.getTranCode()) && StringUtils.isBlank(dto.getTranCode())){
                return Resp.failed("交易码不能为空");
            }
            //1，加载商户私钥
            PrivateKey privateKey = KeyUtils.loadPrivateKey(dto.getPrivateKey());
            //2，不同接口交易码不同
            String tranCode = "R010";
            //3，根据交易码获取不同的提交表单信息，需要完善不同接口的参数值（需客户自己完善具体的参数值）
            String className="com.eidos.blogs.openapi.rest.seckill.request.form."+dto.getTranCode()+"TransForm";
            BaseTransForm base= (BaseTransForm)JSONObject.parseObject(dto.getJsonStr(), Class.forName(className));

            //4，获取加密字段的json串（明文）
            String encryptStr = base.getEncryptJsonStr();
            System.out.println("待加密字符串为："+encryptStr);

            //5，使用平台公钥进行rsa加密
            String msgCipherText = Base64Util.encode(HnapaySign.encryptByPublicKey(encryptStr.getBytes(), dto.getPublicKey())).replace("\n", "").replace("\r", "").replace(" ","");
            System.out.println("加密后字符串为："+msgCipherText);
            base.setMsgCiphertext(msgCipherText);

            //6，使用商户私钥进行签名
            String signValue = Base64Util.encode(HnapaySign.sign(privateKey, base.getCommonSignStr())).replace("\n", "").replace("\r", "").replace(" ","");
            System.out.println("签名后字符串为："+signValue);

            base.setSignValue(signValue);

            //7，构建提交至平台的请求参数
            Map<String,Object> reqMap = base.getCommonReqSignParams();
            reqMap.put("signValue", base.getSignValue());
            reqMap.put("charset", "1");
            reqMap.put("merAttach", "");
            System.out.println("提交字符串为："+ JsonUtils.toJson(reqMap));



//            String response = null;
//            if (base.getSubmitUrl().startsWith("https://")) {
//                HttpsTransport httpsTransport = new HttpsTransport();
//                httpsTransport.setSendEncoding("UTF-8");
//                httpsTransport.setUrl(base.getSubmitUrl());
//                response = (String) httpsTransport.submit(reqMap);
//            } else {
//                HttpClientUtils httpClientUtils = new HttpClientUtils();
//                response = httpClientUtils.submit(reqMap, base.getSubmitUrl());
//            }
//            System.out.println("响应字符串为："+JsonUtils.toJson(response));
//
//            //8，返回参数转map
//            Map<String,Object> responseMap = JsonUtils.jsonToMap(response);
//
//            //9，根据交易码构建不同接口验签明文串
//            String verifyFieldStr = InitForm.getVerifyDataByTranCode(tranCode, responseMap);
//            System.out.println("验签明文字符串为："+verifyFieldStr);
//
//            //10，使用平台公钥进行验签
//            boolean verifyResult = HnapaySign.verify(verifyFieldStr, responseMap.get("signValue").toString());
//            System.out.println("验签结果为："+verifyResult);



            return Resp.success(reqMap);
        } catch (Exception e) {
            e.printStackTrace();
            return Resp.failed();
        }

    }


    public static Object newObj(String className, Object... args) {
        Class[] classes = new Class[args.length];
        for (int i = 0; i < classes.length; i++) {
            classes[i] = args[i].getClass();
        }
        Object obj = null;
        try {
            obj = Class.forName(className).getConstructor(classes).newInstance(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }


}
